package avicit.bdp.dgs.standard.service;

import avicit.bdp.common.base.BaseService;
import avicit.bdp.common.service.service.CommonTypeService;
import avicit.bdp.common.utils.BdpLogUtil;
import avicit.bdp.common.utils.CheckParaUtils;
import avicit.bdp.common.utils.enums.CommonTypeEnums;
import avicit.bdp.common.utils.uploads.FileAdapterUtils;
import avicit.bdp.common.utils.uploads.IFileAdapter;
import avicit.bdp.core.constant.Constants;
import avicit.bdp.core.enums.DataStateEnum;
import avicit.bdp.dgs.standard.dao.StandardDocDao;
import avicit.bdp.dgs.standard.dto.StandardDocDto;
import avicit.platform6.api.system.ConvertColumnClient;
import avicit.platform6.api.system.impl.SystemConstant;
import avicit.platform6.commons.utils.BusinessUtil;
import avicit.platform6.commons.utils.ComUtil;
import avicit.platform6.core.context.ThreadContextHelper;
import avicit.platform6.core.exception.BusinessException;
import avicit.platform6.core.properties.PlatformConstant;
import avicit.platform6.core.rest.msg.QueryRespBean;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

/**
 * @author mayi
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class StandardDocService extends BaseService<StandardDocDao, StandardDocDto> {

  private static final Logger logger = LoggerFactory.getLogger(StandardDocService.class);

  @Resource private StandardDocDao standardDocDao;
  @Resource private CommonTypeService commonTypeService;
  @Resource private ConvertColumnClient convertColumnClient;

  public QueryRespBean<StandardDocDto> getPageList(
      String typeId, String keyWords, Integer status, Integer pageNo, Integer pageSize)
      throws Exception {
    List<String> typeIdList = new ArrayList<>();
    if (StringUtils.isNotEmpty(typeId)) {
      commonTypeService.typeIdConvert(typeId, typeIdList, CommonTypeEnums.DATA_STANDARD_DOC);
    }

    QueryRespBean<StandardDocDto> queryRespBean = new QueryRespBean<>();
    PageHelper.startPage(pageNo, pageSize);
    Page<StandardDocDto> page = standardDocDao.getPageList(typeIdList, keyWords, status, ThreadContextHelper.getWordSecretList());
    try {
      convertUserInfo(page);
    } catch (Exception e) {
      e.printStackTrace();
    }
    queryRespBean.setResult(page);
    BdpLogUtil.log4Query(queryRespBean);
    return queryRespBean;
  }

  private void convertUserInfo(Page<StandardDocDto> page) {
    // 循环组装请求数据
    Map<String, Set<String>> convertFormData = new HashMap<>(16);
    for (StandardDocDto standardDocDto : page) {
      BusinessUtil.createConvertSet(
          convertFormData, SystemConstant.USER, standardDocDto.getCreatedBy());
      BusinessUtil.createConvertSet(
          convertFormData, SystemConstant.USER, standardDocDto.getLastUpdatedBy());
      BusinessUtil.createConvertSet(convertFormData, Constants.BDP_DATA_SECRET_LEVEL_KEY, standardDocDto.getSecretLevel());
    }
    if (convertFormData.size() > 0) {
      Map<String, Map<String, String>> convertResultData =
          convertColumnClient.replace(convertFormData);
      for (StandardDocDto standardDocDto : page) {
        standardDocDto.setStatusString(DataStateEnum.getDescByCode(standardDocDto.getStatus()));
        standardDocDto.setCreatedBy(
            BusinessUtil.convertFormat(
                convertResultData, SystemConstant.USER, standardDocDto.getCreatedBy()));

        standardDocDto.setLastUpdatedBy(
            BusinessUtil.convertFormat(
                convertResultData, SystemConstant.USER, standardDocDto.getLastUpdatedBy()));
        standardDocDto.setSecretLevelName(BusinessUtil.convertFormat(convertResultData, Constants.BDP_DATA_SECRET_LEVEL_KEY, standardDocDto.getSecretLevel()));
      }
    }
  }

  public String save(String typeId, String code, String name, String remark, String secretLevel, MultipartFile file) {

    CheckParaUtils.checkStringValidity(typeId, logger, "分类不能为空");
    CheckParaUtils.checkObjectValidity(code, logger, "文件编码不能为空");
    CheckParaUtils.checkObjectValidity(file, logger, "文件不能为空");

    StandardDocDto standardDocDto = new StandardDocDto();
    standardDocDto.setTypeId(typeId);
    standardDocDto.setCode(code);
    standardDocDto.setName(name);
    standardDocDto.setRemark(remark);

    checkNameUnique(standardDocDto);
    checkCodeUnique(standardDocDto);

    standardDocDto.setId(ComUtil.getId());
    standardDocDto.setStatus(DataStateEnum.UNDER_EDITING.getCode());
    standardDocDto.setSecretLevel(secretLevel);

    try {
      Date d = new Date();
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
      String dateNowStr = sdf.format(d);
      String originalFilename = file.getOriginalFilename();

      String fullName =
          Constants.STANDARD_DOC_UPLOAD_TOP_PATH
              + Constants.SINGLE_SLASH
              + dateNowStr
              + Constants.SINGLE_SLASH
              + originalFilename;

      IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(null);
      Objects.requireNonNull(fileAdapter, "文件存储系统不存在");
      fileAdapter.upload(file.getInputStream(), fullName);

      standardDocDto.setFilePath(fullName);

      this.insert(standardDocDto);
      log4Insert(standardDocDto);

      return standardDocDto.getId();
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  public void update(String id, String code, String name, String remark, MultipartFile file) {

    CheckParaUtils.checkStringValidity(id, logger, "ID不能为空");
    CheckParaUtils.checkObjectValidity(code, logger, "文件编码不能为空");

    StandardDocDto oldDto = this.selectByPrimaryKey(id);
    CheckParaUtils.checkDbObjectValidity(
        oldDto, logger, String.format("没有查到数据，请确保id:%s的数据是否存在", id));

    StandardDocDto standardDocDto = new StandardDocDto();
    BeanUtils.copyProperties(oldDto, standardDocDto);
    standardDocDto.setCode(code);
    standardDocDto.setName(name);
    standardDocDto.setRemark(remark);

    // 校验标准名称唯一性
    if (!standardDocDto.getName().equals(oldDto.getName())) {
      checkNameUnique(standardDocDto);
    }

    // 校验标准编码唯一性
    if (!standardDocDto.getCode().equals(oldDto.getCode())) {
      checkCodeUnique(standardDocDto);
    }

    if (file != null) {
      try {
        Date d = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dateNowStr = sdf.format(d);
        String originalFilename = file.getOriginalFilename();

        String fullName =
            Constants.STANDARD_DOC_UPLOAD_TOP_PATH
                + Constants.SINGLE_SLASH
                + dateNowStr
                + Constants.SINGLE_SLASH
                + originalFilename;

        IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(null);
        Objects.requireNonNull(fileAdapter, "文件存储系统不存在");
        fileAdapter.upload(file.getInputStream(), fullName);

        fileAdapter.delete(oldDto.getFilePath(), false);

        standardDocDto.setFilePath(fullName);

      } catch (IOException e) {
        throw new RuntimeException(e);
      }
    }

    standardDocDto.setCreationDate(oldDto.getCreationDate());
    this.updateByPrimaryKey(standardDocDto);
    BdpLogUtil.log4Update(standardDocDto, oldDto);
  }

  public Boolean batchDelete(String ids) throws IOException {
    CheckParaUtils.checkStringValidity(ids, logger, "没有传入待删除的ID");
    String[] idArr = ids.split(Constants.COMMA);
    IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(null);
    Objects.requireNonNull(fileAdapter, "文件存储系统不存在");
    for (String id : idArr) {
      StandardDocDto standardDocDto = this.selectByPrimaryKey(id);
      CheckParaUtils.checkDbObjectValidity(
          standardDocDto, logger, String.format("没有查到数据，请确保id:%s的数据是否存在", id));

      this.mapper.deleteByPrimaryKey(id);
      fileAdapter.delete(standardDocDto.getFilePath(), false);
      // 记录日志
      BdpLogUtil.log4Delete(standardDocDto);
    }
    return true;
  }

  /**
   * 校验名称唯一性
   *
   * @param standardDocDto 检测对象
   */
  private void checkNameUnique(StandardDocDto standardDocDto) {
    if (standardDocDto != null) {
      if (StringUtils.isEmpty(standardDocDto.getName())) {
        throw new BusinessException("名称不能为空");
      }

      StandardDocDto paramName = new StandardDocDto();
      paramName.setName(standardDocDto.getName());
      if (this.selectCount(paramName) > 0) {
        throw new BusinessException("名称[" + standardDocDto.getName() + "]已存在");
      }
    }
  }

  /**
   * 校验代码唯一性
   *
   * @param standardDocDto 检测对象
   */
  private void checkCodeUnique(StandardDocDto standardDocDto) {
    if (standardDocDto != null) {
      if (StringUtils.isEmpty(standardDocDto.getCode())) {
        throw new BusinessException("代码不能为空");
      }

      StandardDocDto paramCode = new StandardDocDto();
      paramCode.setCode(standardDocDto.getCode());
      if (this.selectCount(paramCode) > 0) {
        throw new BusinessException("编码[" + standardDocDto.getCode() + "]已存在");
      }
    }
  }

  public void downLoad(String id, HttpServletRequest request, HttpServletResponse response)
      throws Exception {
    StandardDocDto standardDocDto = this.selectByPrimaryKey(id);
    if (standardDocDto == null) {
      throw new BusinessException("数据不存在");
    }

    if (StringUtils.isEmpty(standardDocDto.getFilePath())) {
      throw new BusinessException("该标准文档不存在附件");
    }

    String logTitle = "下载标准文档，id为【" + id + "】";
    BdpLogUtil.log("标准文档模块", logTitle, PlatformConstant.OpType.select);

    IFileAdapter fileAdapter = FileAdapterUtils.getFileAdapterByProject(null);
    Objects.requireNonNull(fileAdapter, "文件存储系统不存在");
    fileAdapter.downloadFile(standardDocDto.getFilePath(), request, response);
  }
}
